home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / IcnsImagePlugin.py < prev    next >
Text File  |  2006-12-03  |  6KB  |  212 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: ImImagePlugin.py 2134 2004-10-06 08:55:20Z fredrik $
  4. #
  5. # Mac OS X icns file decoder, based on icns.py by Bob Ippolito.
  6. #
  7. # history:
  8. # 2004-10-09 fl   Turned into a PIL plugin; removed 2.3 dependencies.
  9. #
  10. # Copyright (c) 2004 by Bob Ippolito.
  11. # Copyright (c) 2004 by Secret Labs.
  12. # Copyright (c) 2004 by Fredrik Lundh.
  13. #
  14. # See the README file for information on usage and redistribution.
  15. #
  16.  
  17. import Image, ImageFile
  18. import string, struct
  19.  
  20. HEADERSIZE = 8
  21.  
  22. def nextheader(fobj):
  23.     return struct.unpack('>4sI', fobj.read(HEADERSIZE))
  24.  
  25. def read_32t(fobj, (start, length), (width, height)):
  26.     # The 128x128 icon seems to have an extra header for some reason.
  27.     fobj.seek(start)
  28.     sig = fobj.read(4)
  29.     if sig != '\x00\x00\x00\x00':
  30.         raise SyntaxError, 'Unknown signature, expecting 0x00000000'
  31.     return read_32(fobj, (start + 4, length - 4), (width, height))
  32.  
  33. def read_32(fobj, (start, length), size):
  34.     """
  35.     Read a 32bit RGB icon resource.  Seems to be either uncompressed or
  36.     an RLE packbits-like scheme.
  37.     """
  38.     fobj.seek(start)
  39.     sizesq = size[0] * size[1]
  40.     if length == sizesq * 3:
  41.         # uncompressed ("RGBRGBGB")
  42.         indata = fobj.read(length)
  43.         im = Image.frombuffer("RGB", size, indata, "raw", "RGB", 0, 1)
  44.     else:
  45.         # decode image
  46.         im = Image.new("RGB", size, None)
  47.         for band_ix in range(3):
  48.             data = []
  49.             bytesleft = sizesq
  50.             while bytesleft > 0:
  51.                 byte = fobj.read(1)
  52.                 if not byte:
  53.                     break
  54.                 byte = ord(byte)
  55.                 if byte & 0x80:
  56.                     blocksize = byte - 125
  57.                     byte = fobj.read(1)
  58.                     for i in range(blocksize):
  59.                         data.append(byte)
  60.                 else:
  61.                     blocksize = byte + 1
  62.                     data.append(fobj.read(blocksize))
  63.                 bytesleft = bytesleft - blocksize
  64.                 if bytesleft <= 0:
  65.                     break
  66.             if bytesleft != 0:
  67.                 raise SyntaxError(
  68.                     "Error reading %r channel [%r]" % (channel, bytesleft)
  69.                     )
  70.             band = Image.frombuffer(
  71.                 "L", size, string.join(data, ""), "raw", "L", 0, 1
  72.                 )
  73.             im.im.putband(band.im, band_ix)
  74.     return {"RGB": im}
  75.  
  76. def read_mk(fobj, (start, length), size):
  77.     # Alpha masks seem to be uncompressed
  78.     fobj.seek(start)
  79.     band = Image.frombuffer(
  80.         "L", size, fobj.read(size[0]*size[1]), "raw", "L", 0, 1
  81.         )
  82.     return {"A": band}
  83.  
  84. class IcnsFile:
  85.  
  86.     SIZES = {
  87.         (128, 128): [
  88.             ('it32', read_32t),
  89.             ('t8mk', read_mk),
  90.         ],
  91.         (48, 48): [
  92.             ('ih32', read_32),
  93.             ('h8mk', read_mk),
  94.         ],
  95.         (32, 32): [
  96.             ('il32', read_32),
  97.             ('l8mk', read_mk),
  98.         ],
  99.         (16, 16): [
  100.             ('is32', read_32),
  101.             ('s8mk', read_mk),
  102.         ],
  103.     }
  104.  
  105.     def __init__(self, fobj):
  106.         """
  107.         fobj is a file-like object as an icns resource
  108.         """
  109.         # signature : (start, length)
  110.         self.dct = dct = {}
  111.         self.fobj = fobj
  112.         sig, filesize = nextheader(fobj)
  113.         if sig != 'icns':
  114.             raise SyntaxError, 'not an icns file'
  115.         i = HEADERSIZE
  116.         while i < filesize:
  117.             sig, blocksize = nextheader(fobj)
  118.             i = i + HEADERSIZE
  119.             blocksize = blocksize - HEADERSIZE
  120.             dct[sig] = (i, blocksize)
  121.             fobj.seek(blocksize, 1)
  122.             i = i + blocksize
  123.  
  124.     def itersizes(self):
  125.         sizes = []
  126.         for size, fmts in self.SIZES.items():
  127.             for (fmt, reader) in fmts:
  128.                 if self.dct.has_key(fmt):
  129.                     sizes.append(size)
  130.                     break
  131.         return sizes
  132.  
  133.     def bestsize(self):
  134.         sizes = self.itersizes()
  135.         if not sizes:
  136.             raise SyntaxError, "No 32bit icon resources found"
  137.         return max(sizes)
  138.  
  139.     def dataforsize(self, size):
  140.         """
  141.         Get an icon resource as {channel: array}.  Note that
  142.         the arrays are bottom-up like windows bitmaps and will likely
  143.         need to be flipped or transposed in some way.
  144.         """
  145.         dct = {}
  146.         for code, reader in self.SIZES[size]:
  147.             desc = self.dct.get(code)
  148.             if desc is not None:
  149.                 dct.update(reader(self.fobj, desc, size))
  150.         return dct
  151.  
  152.     def getimage(self, size=None):
  153.         if size is None:
  154.             size = self.bestsize()
  155.         channels = self.dataforsize(size)
  156.         im = channels.get("RGB").copy()
  157.         try:
  158.             im.putalpha(channels["A"])
  159.         except KeyError:
  160.             pass
  161.         return im
  162.  
  163. ##
  164. # Image plugin for Mac OS icons.
  165.  
  166. class IcnsImageFile(ImageFile.ImageFile):
  167.     """
  168.     PIL read-only image support for Mac OS .icns files.
  169.     Chooses the best resolution, but will possibly load
  170.     a different size image if you mutate the size attribute
  171.     before calling 'load'.
  172.  
  173.     The info dictionary has a key 'sizes' that is a list
  174.     of sizes that the icns file has.
  175.     """
  176.  
  177.     format = "ICNS"
  178.     format_description = "Mac OS icns resource"
  179.  
  180.     def _open(self):
  181.         self.icns = IcnsFile(self.fp)
  182.         self.mode = 'RGBA'
  183.         self.size = self.icns.bestsize()
  184.         self.info['sizes'] = self.icns.itersizes()
  185.         # Just use this to see if it's loaded or not yet.
  186.         self.tile = ('',)
  187.  
  188.     def load(self):
  189.         Image.Image.load(self)
  190.         if not self.tile:
  191.             return
  192.         self.load_prepare()
  193.         # This is likely NOT the best way to do it, but whatever.
  194.         im = self.icns.getimage(self.size)
  195.         self.im = im.im
  196.         self.mode = im.mode
  197.         self.size = im.size
  198.         self.fp = None
  199.         self.icns = None
  200.         self.tile = ()
  201.         self.load_end()
  202.  
  203.  
  204. Image.register_open("ICNS", IcnsImageFile, lambda x: x[:4] == 'icns')
  205. Image.register_extension("ICNS", '.icns')
  206.  
  207. if __name__ == '__main__':
  208.     import os, sys
  209.     im = Image.open(open(sys.argv[1], "rb"))
  210.     im.save("out.png")
  211.     os.startfile("out.png")
  212.